﻿#define _CRT_SECURE_NO_WARNINGS 1

//包装器 function和bind

//包装可调用对象  函数指针 仿函数 lambda表达式

#include<iostream>
#include<functional>
using namespace std;

/*
std::function 是⼀个类模板，也是⼀个包装器。 std::function 的实例对象可以包装存
储其他的可以调⽤对象，包括函数指针、仿函数、 lambda 、 bind 表达式等，存储的可调⽤对
象被称为 std::function 的⽬标。
*/

//int f(int a, int b)  //函数指针
//{
//	return a + b;
//}
//
//struct Functor //仿函数
//{
//public:
//	int operator() (int a, int b)
//	{
//		return a + b;
//	}
//};
//
//class Plus  //类
//{
//public:
//	Plus(int n = 10)
//		:_n(n)
//	{}
//
//	static int plusi(int a, int b)
//	{
//		return a + b;
//	}
//
//	double plusd(double a, double b)
//	{
//		return (a + b) * _n;
//	}
//private:
//	int _n;
//};
//
//int main()
//{
//	//function的语法   function<返回值(参数)>
//
//	// 包装各种可调用对象
//	function<int(int, int)> f1 = f; //函数名会隐式转换为指针
//	function<int(int, int)> f2 = Functor();
//	function<int(int, int)> f3 = [](int a, int b) {return a + b; };
//	cout << f1(1, 1) << endl;
//	cout << f2(1, 1) << endl;
//	cout << f3(1, 1) << endl;
//
//	// 包装静态成员函数
//	// 成员函数要指定类域并且前面加&才能获取地址
//	function<int(int, int)> f4 = &Plus::plusi;
//	cout << f4(1, 1) << endl;
//
//	//非静态的成员函数 注意参数有一个this指针
//	//本质是通过其去调用成员函数 因此不一定非要传指针
//	function<double(Plus*, double, double)> f5 = &Plus::plusd;
//	Plus ps;
//	cout << f5(&ps, 1, 1) << endl;
//
//	//
//	function<double(Plus&, double, double)> f6 = &Plus::plusd;
//	cout << f6(ps, 1, 1) << endl;
//	
//	//也可以传匿名对象和右值对象
//	function<double(Plus&&, double, double)> f7 = &Plus::plusd;
//	cout << f7(Plus(), 1, 1) << endl;
//
//	return 0;
//}

#include <vector>
#include <stack>
#include <map>
#include <string>
//function应用
/*
给你一个字符串数组 tokens ，表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意：

有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数（运算对象）都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。*/
class Solution {
public:
	int evalRPN(vector<string>& tokens) {
		stack<int> st;
		map<string, function<int(int, int)>> m = {
			{"+",[](int x, int y) {return x + y; }},  //包装lambda对象
			{"-",[](int x, int y) {return x - y; }},
			{"*",[](int x, int y) {return x * y; }},
			{"/",[](int x, int y) {return x / y; }}
		};
		for (auto& e : tokens)
		{
			if (m.count(e))
			{
				//操作符
				int right = st.top();
				st.pop();
				int left = st.top();
				st.pop();
				st.push(m[e](left, right));
			}
			else
			{
				st.push(stoi(e));
			}
		}
		return st.top();
	}
};


//bind
/*bind 是⼀个函数模板，它也是⼀个可调⽤对象的包装器，可以把他看做⼀个函数适配器，对接收
的fn可调⽤对象进⾏处理后返回⼀个可调⽤对象。 bind 可以⽤来调整参数个数和参数顺序。*/

/*调⽤bind的⼀般形式： auto newCallable = bind(callable,arg_list); 其中
newCallable本⾝是⼀个可调⽤对象，arg_list是⼀个逗号分隔的参数列表，对应给定的callable的
参数。当我们调⽤newCallable时，newCallable会调⽤callable，并传给它arg_list中的参数。*/

//arg_list中的参数可能包含形如_n的名字，其中n是⼀个整数，这些参数是占位符

//展开命名空间 
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;

int Sub(int a, int b)
{
	return (a - b) * 10;
}

int SubX(int a, int b, int c)
{
	return (a - b - c) * 10;
}

class Plus
{
public:
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return a + b;
	}
};

int main()
{
	auto sub1 = bind(Sub, _1, _2);
	cout << sub1(10, 5) << endl;  //10代表_1 5代表_2  10会放在_1占的那个位置里 5同上

	// bind 本质返回的一个仿函数对象
	// 调整参数顺序（不常用）
	// _1代表第一个实参
	// _2代表第二个实参
	// ...
	// 调整参数顺序
	auto sub2 = bind(Sub, _2, _1);
	//这里的sub2里面的参数按顺序传递给bind中的_1 _2 _3等等 而bind中的参数则是顺序传递给Sub的 也就是_2是Sub的第一个参数 _1是Sub的第二个参数
	cout << sub2(10, 5) << endl;  //这时候10还是_1 5是_2  但是在调用Sub的里面_1和_2换位置了 于是是-50

	// 调整参数个数
	// 绑死a
	//bind在向上传达时候Sub中的a永远是100 
	auto sub3 = bind(Sub, 100, _1);
	cout << sub3(5) << endl;

	// 绑死b
	auto sub4 = bind(Sub, _1, 100);
	cout << sub4(5) << endl;

	// 分别绑死第123个参数
	auto sub5 = bind(SubX, 100, _1, _2);
	cout << sub5(5, 1) << endl;
	auto sub6 = bind(SubX, _1, 100, _2);
	cout << sub6(5, 1) << endl;
	auto sub7 = bind(SubX, _1, _2, 100);
	cout << sub7(5, 1) << endl;

	// 成员函数对象进行绑死，就不需要每次都传递了
	function<double(Plus&&, double, double)> f6 = &Plus::plusd;
	Plus pd;
	cout << f6(move(pd), 1.1, 1.1) << endl;  //之前这样的时候每次都要传对象
	cout << f6(Plus(), 1.1, 1.1) << endl;

	// bind一般用于，绑死一些固定参数
	//这里绑死 每次固定第一个参数都是匿名对象Plus()  这样就不用那样繁琐的传了
	function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);  //这里也可以用auto接收
	cout << f7(1.1, 1.1) << endl;

	// 计算复利的lambda
	auto func1 = [](double rate, double money, int year)->double {
		double ret = money;
		for (int i = 0; i < year; i++)
		{
			ret += ret * rate; //计算复利
		}
		return ret - money;
	};
	cout << func1(0.1, 1000000, 30) << endl;

	// 绑死一些参数，实现出支持不同年化利率，不同金额和不同年份计算出复利的结算利息
	function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);  //这样绑定后只需要传本金这个参数
	function<double(double)> func5_2_5 = bind(func1, 0.025, _1, 5);
	function<double(double)> func10_3_5 = bind(func1, 0.035, _1, 10);
	function<double(double)> func20_5_5 = bind(func1, 0.055, _1, 20);
	
	cout << func3_1_5(1000000) << endl;  //存3年 1.5%的利润 1000000本金
	cout << func5_2_5(1000000) << endl;
	cout << func10_3_5(1000000) << endl;
	cout << func20_5_5(1000000) << endl;

	return 0;
}

